package org.shangrila.app.sys.shiro;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;

/**
 * 配置shiro
 * @author 
 */
@Configuration
public class ShiroConfig {
    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题:Filter工厂，设置对应的过滤条件和跳转条件
     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，在初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
     *
     * Filter Chain定义说明 
     * 1、一个URL可以配置多个Filter，使用逗号分隔 
     * 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     *
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/pages/login.jsf");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/pages/home.jsf");
        // 未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        //拦截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/pages/login.xhtml", "anon");
        filterChainDefinitionMap.put("/resources/**", "anon");
        filterChainDefinitionMap.put("/demo/**", "anon");
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/template/**", "anon");
        
        filterChainDefinitionMap.put("/pages/demo/**", "anon");       
        filterChainDefinitionMap.put("/pages/*.xhtml", "anon");
        filterChainDefinitionMap.put("/pages/mobile/**", "anon");

        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");

        filterChainDefinitionMap.put("/add", "perms[权限添加]");

        // 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边: 这是一个坑呢，一不小心代码就不好使了;
        // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        //filterChainDefinitionMap.put("/**", "authc");
        //filterChainDefinitionMap.put("/**", "anon");

        filterChainDefinitionMap.put("/pages/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        System.out.println("shiroFilterFactoryBean registers successfully.");
        return shiroFilterFactoryBean;
    }

    //SecurityManager:权限管理，配置主要是Realm的管理认证
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(appShiroRealm()); 
        RememberMeManager rememberMeManager = new RememberMeManager() {
			
			@Override
			public void onSuccessfulLogin(Subject arg0, AuthenticationToken arg1, AuthenticationInfo arg2) {
				
			}
			
			@Override
			public void onLogout(Subject arg0) {
				
			}
			
			@Override
			public void onFailedLogin(Subject arg0, AuthenticationToken arg1, AuthenticationException arg2) {
				
			}
			
			@Override
			public PrincipalCollection getRememberedPrincipals(SubjectContext arg0) {
				return null;
			}
			
			@Override
			public void forgetIdentity(SubjectContext arg0) {				
				
			}
		};
		securityManager.setRememberMeManager(rememberMeManager );
        return securityManager;
    }

    //将自己的验证方式加入容器: 身份认证realm;(这个需要自己写，账号密码校验；权限等)
    @Bean
    public AppShiroRealm appShiroRealm() {
    	AppShiroRealm appShiroRealm = new AppShiroRealm();
        return appShiroRealm;
    }
    
    //加入注解的使用，不加入这个注解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    
}
